<?php
// +----------------------------------------------------------------------
// | 服务
// +----------------------------------------------------------------------
declare(strict_types=1);

namespace app\service;

use app\model\AccessTokensModel;
use DateTimeImmutable;
use think\db\Query;

/**
 * Refresh Token 生成与认证
 *
 * Class RefreshTokenService
 * @package app\service
 */
class RefreshTokenService
{

    /**
     * 获取Token过期时间
     * 
     * @return string
     */
    private static function getTokenExpiresTime(): string
    {
        $now = new DateTimeImmutable();
        $day = $now->modify('+' . env('jwt.refresh_day') . ' day');
        return $day->format('Y-m-d H:i:s');
    }

    /**
     * 获取随机Token（32位）
     * 
     * @return string
     */
    private static function geneRandomToken(): string
    {
        return md5(uniqid((string)mt_rand(), true));
    }

    /**
     * 生成用户Token
     * 
     * @param int $uid 用户ID
     * @param string $salt 加盐参数
     * 
     * @return string
     */
    public static function geneUserToken(int $uid, string $salt): string
    {
        $token = self::geneRandomToken();
        // 删除已过期的token
        AccessTokensModel::destroy(function (Query $query) use ($uid, $token) {
            $query->where('type', 'refresh_token');
            $query->where('user_id', $uid);
            $query->whereTime('expire_time', '<', date('Y-m-d H:i:s'));
        });
        // 生成新的token
        AccessTokensModel::create([
            'type'        => 'refresh_token',
            'user_id'     => $uid,
            'salt'        => $salt,
            'token'       => $token,
            'expire_time' => self::getTokenExpiresTime(),
        ]);
        return $token;
    }

    /**
     * 刷新用户Token（失败返回bool）
     * 
     * @param int $uid 用户ID
     * @param string $salt 加盐参数
     * @param string $token 生成的Token
     * 
     * @return string|bool
     */
    public static function refreshUserToken(int $uid, string $salt, string $token): string|bool
    {
        $new_token = self::geneRandomToken();
        $info = AccessTokensModel::where([
            'type'    => 'refresh_token',
            'user_id' => $uid,
            'salt'    => $salt,
            'token'   => $token
        ])->find();
        if ($info) {
            // 判断是否过期
            if ($info->expire_time > date('Y-m-d H:i:s')) {
                $info->token = $new_token;
                $info->expire_time = self::getTokenExpiresTime();
                $info->save();
                return $new_token;
            }
        }
        return false;
    }

    /**
     * 验证用户Token
     * 
     * @param int $uid 用户ID
     * @param string $salt 加密盐
     * @param string $token 生成的Token
     * 
     * @return bool
     */
    public static function verifyUserToken(int $uid, string $salt, string $token): bool
    {
        if (!$token) {
            return false;
        }
        $info = AccessTokensModel::where([
            'type' => 'refresh_token',
            'user_id' => $uid,
            'salt' => $salt,
            'token' => $token
        ])->find();
        if ($info) {
            // 验证是否过期
            if ($info->expire_time > date('Y-m-d H:i:s')) {
                return true;
            }
        }
        return false;
    }

    /**
     * 移除用户Token
     * 
     * @param int $uid 用户ID
     * @param string $salt 加密盐
     * @param string $token 生成的Token
     * 
     * @return
     */
    public static function removeUserToken(int $uid, string $salt, string $token): void
    {
        AccessTokensModel::where([
            'type' => 'refresh_token',
            'salt' => $uid . '_' . $salt,
            'token' => $token
        ])->delete();
    }
}
